package cc.shacocloud.mirage.kotlin

import cc.shacocloud.mirage.core.support.MirageHolder
import io.vertx.core.Context
import io.vertx.core.Future
import io.vertx.core.Promise
import io.vertx.core.Vertx
import io.vertx.kotlin.coroutines.await
import io.vertx.kotlin.coroutines.dispatcher
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED

/**
 * 获取当前上下文
 */
fun currentContext(): Context {
    return Vertx.currentContext() ?: throw IllegalStateException("必须在 VertxThread 中调用该方法！")
}

/**
 * 获取当前上下文，如果不存在则创建
 */
fun currentContextOrCreate(): Context {
    return Vertx.currentContext() ?: MirageHolder.getVertx().orCreateContext
}

/**
 * 基于 kotlin 的 vertx 协程调度方法封装，没有返回值的内部协程函数，
 * 适用于类似 {@link io.vertx.core.Handler#findPathResource} 方法上的使用
 *
 * @see <a href="https://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/">文档</>
 */
fun mirageLaunchScope(fn: suspend (coroutineContext: CoroutineContext) -> Unit) {
    mirageLaunch(currentContextOrCreate(), fn).onFailure { it.printStackTrace() }
}

/**
 * 基于 kotlin 的 vertx 协程调度方法封装，没有返回值的协程函数
 *
 * @see <a href="https://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/">文档</>
 */
fun mirageLaunchUnit(fn: suspend (coroutineContext: CoroutineContext) -> Unit): Future<Unit> {
    return mirageLaunch(currentContextOrCreate(), fn)
}

/**
 * 基于 kotlin 的 vertx 协程调度方法封装
 *
 * @see <a href="https://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/">文档</>
 */
fun <R> mirageLaunch(fn: suspend (coroutineContext: CoroutineContext) -> R): Future<R> {
    return mirageLaunch(currentContextOrCreate(), fn)
}

/**
 * 基于 kotlin 的 vertx 协程调度方法封装
 *
 * @see <a href="https://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/">文档</>
 */
@OptIn(DelicateCoroutinesApi::class)
fun <R> mirageLaunch(
    context: Context,
    fn: suspend (coroutineContext: CoroutineContext) -> R
): Future<R> {
    val promise = Promise.promise<R>()

    GlobalScope.launch(context.dispatcher() as CoroutineContext) {
        try {
            val r = fn(this.coroutineContext)
            promise.complete(r)
        } catch (e: Exception) {
            promise.fail(e)
        }
    }

    return promise.future()
}

/**
 * 反射执行指定方法，支持 kotlin 协程方法调用
 */
suspend fun doMethodInvoke(bean: Any, method: Method, vararg providedArgs: Any?): Any {
    return doMethodInvoke(currentContext().dispatcher() as CoroutineContext, bean, method, *providedArgs)
}

/**
 * 反射执行指定方法，支持 kotlin 协程方法调用
 */
@Suppress("UNCHECKED_CAST")
suspend fun doMethodInvoke(
    coroutineContext: CoroutineContext,
    bean: Any,
    method: Method,
    vararg providedArgs: Any?
): Any {
    if ((!Modifier.isPublic(method.modifiers) || !Modifier.isPublic(method.declaringClass.modifiers))
        && !method.canAccess(bean)
    ) {
        method.isAccessible = true
    }

    // 如果是kotlin的协程方法
    if (isSuspendingFunction(method)) {
        var args = providedArgs
        val mirageContinuation: MirageContinuation

        // 如果最后一个参数是 Continuation 类型则认为参数是完整，则对用户传入的 Continuation 进行包装
        val param = if (args.isNotEmpty()) args[args.size - 1] else null
        if (param is Continuation<*>) {

            if (param is MirageContinuation) {
                mirageContinuation = param
            } else {
                mirageContinuation = MirageContinuationWrapper(param as Continuation<Any>)
                args = arrayOf(*providedArgs)
                args[args.size - 1] = mirageContinuation
            }

        } else {
            mirageContinuation = MirageContinuationContext(coroutineContext)
            args = arrayOf(*providedArgs, mirageContinuation)
        }

        var result = method.invoke(bean, *args)

        // 如果返回暂停协程状态则等待 coroutineFun 的结果
        if (COROUTINE_SUSPENDED == result) {
            result = mirageContinuation.awaitResult()
        }

        return result
    }

    return method.invoke(bean, *providedArgs)
}

/**
 *  基于 Continuation 接口抽象
 */
interface MirageContinuation : Continuation<Any> {

    /**
     * 转为 {@link Future} 对象
     */
    fun toFuture(): Future<Any>

    /**
     * 等待处理结果
     */
    suspend fun awaitResult(): Any
}

/**
 *  基于 Continuation 的实现，用于在反射中等待 挂起方法的处理结果
 */
abstract class AbstractMirageContinuation : MirageContinuation {

    private val promise: Promise<Any> = Promise.promise()

    override fun resumeWith(result: Result<Any>) {
        result.onFailure { promise.fail(it) }
            .onSuccess { promise.complete(it) }
    }

    /**
     * 转为 {@link Future} 对象
     */
    override fun toFuture(): Future<Any> {
        return promise.future()
    }

    /**
     * 等待处理结果
     */
    override suspend fun awaitResult(): Any {
        return toFuture().await()
    }
}

/**
 * 基于 Continuation 的委托模式
 */
class MirageContinuationWrapper(private val continuation: Continuation<Any>) : AbstractMirageContinuation() {

    override val context: CoroutineContext get() = continuation.context

    override fun resumeWith(result: Result<Any>) {
        super.resumeWith(result)
        continuation.resumeWith(result)
    }
}

/**
 *  基于 Continuation 的实现，用于在反射中等待 挂起方法的处理结果
 */
class MirageContinuationContext(private val coroutineContext: CoroutineContext) : AbstractMirageContinuation() {

    override val context: CoroutineContext get() = coroutineContext

}